#pragma once
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include "log.hpp"
#include <errno.h>
#include "Socket.hpp"
#include <memory>

const int defaultsize=1024;//这是select的默认监听数量，1024个比特位
const int defaultfill=-1;//默认填充位
LOG lg(PRINT_TO_SCREEN);

//select的缺点：
//1. 每次调用select都要重新设置fd_set，开销较大
//2. fd数量受限于1024个，等待fd有上限
//3. 输入输出型参数较多，数据拷贝的频率比较高，如果fd很多，效率较低
//4. 如果不想用多线程，或者线程池，select是一个不错的选择
//5. 为了解决fd数量受限的问题，可以使用poll或者epoll
//注意：这里只能处理读事件，如果要处理写事件或者异常事件，需要再定义两个fd_set，并且fd_array中也要保存写事件和异常事件的状态

class SelectServer
{
public:
    SelectServer(uint16_t port=8080)
        : port_(port)
    {

    }

    void Init()
    {
        listensocket_.Socket();
        listensocket_.Bind(port_);
        listensocket_.Listen();

        //初始化fd数组,全部设置为-1
        for(int i=0;i<defaultsize;++i)
        {
            fd_array[i]=defaultfill;
        }
    }   

    void PrintFd()
    {
        for(int i=0;i<defaultsize;++i)
        {
            if(fd_array[i]!=defaultfill)
            {
                std::cout<<fd_array[i]<<" ";
            }
        }
    }

    void HanderEvent(fd_set& rfds)
    {
        for(int i=0;i<defaultsize;i++)
        {
            int fd=fd_array[i];
            if(fd==defaultfill) continue;//跳过未使用的位
            else
            {
                if(fd==listensocket_.Getsocketfd())
                {
                    if(FD_ISSET(fd,&rfds))//监听socket有事件
                    {
                        int clientfd;
                        std::string client_ip;
                        uint16_t client_port;
                        if(listensocket_.Accept(clientfd,client_ip,client_port))
                        {
                            std::cout<<"Accept a new client: "<<client_ip<<":"<<client_port<<std::endl;
                            //将新的客户端socket放到数组中
                            int j=0;
                            for(;j<defaultsize;++j)
                            {
                                if(fd_array[j]==defaultfill)
                                {
                                    fd_array[j]=clientfd;
                                    break;
                                }
                            }
                            if(j==defaultsize)
                            {
                                std::cerr<<"fd_array is full, cannot accept more client"<<std::endl;
                                close(clientfd);
                            }
                            PrintFd();
                        }
                    }
                }
                else//普通的客户端socket
                {
                    if(FD_ISSET(fd,&rfds))//客户端socket有事件
                    {
                        char buffer[1024];
                        ssize_t n=read(fd,buffer,sizeof(buffer)-1);
                        if(n>0)
                        {
                            buffer[n]='\0';
                            std::cout<<"Received from client fd "<<fd<<": "<<buffer<<std::endl;
                            //回显数据
                            //write(fd,buffer,n);
                        }
                        else if(n==0)
                        {
                            //客户端关闭了连接
                            std::cout<<"Client fd "<<fd<<" closed the connection"<<std::endl;
                            close(fd);
                            fd_array[i]=defaultfill;//将该位置重新设置为-1，表示未使用
                        }
                        else
                        {
                            std::cerr<<"read error on fd "<<fd<<", errno: "<<errno<<", errstring: "<<strerror(errno)<<std::endl;
                            close(fd);
                            fd_array[i]=defaultfill;//将该位置重新设置为-1，表示未使用
                        }
                    }
                }
            }
        }
    }

    void Start()
    {
        int fd=listensocket_.Getsocketfd();
        fd_array[0]=fd;//把监听socket放到数组的第一个位置
        while(1)
        {
            sleep(1);
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd=fd_array[0];
            //这里每次都要重新设置，因为select调用后，rfds会被内核修改
            for(int i=0;i<defaultsize;++i)
            {
                if(fd_array[i]!=defaultfill)
                {
                    FD_SET(fd_array[i],&rfds);
                    if(fd_array[i]>maxfd) maxfd=fd_array[i];
                }
            }
            //找出最大的fd，select的第一个参数是最大的fd+1
            struct timeval tv={0,0};//设置为0表示发现就立即返回
            int n=select(maxfd+1,&rfds, nullptr, nullptr, &tv);
            //select会对rfds进行修改，返回后只保留有事件的fd
            switch(n)
            {
                case 0:
                    std::cout<<"select timeout"<<std::endl;
                    break;
                case -1:
                    if(errno==EWOULDBLOCK)//这里是底层还未就绪
                    {
                        std::cout<<"select interrupted by signal"<<std::endl;
                        continue;
                    }
                    else
                    {
                        //否则是真的出错了
                        std::cerr<<"select error, errno: "<<errno<<", errstring: "<<strerror(errno)<<std::endl;
                    }
                    break;
                default:
                    HanderEvent(rfds);
                    break;
            }
        }

    }

    ~SelectServer()
    {

    }
private:
    Sockets listensocket_;
    uint16_t port_;
    int fd_array[defaultsize];
};